<?php
/** 应用公共文件  */
use think\facade\Cache;
use think\facade\Config;
use think\facade\Request;
use app\adminplatform\model\System;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
/** 状态常量 */
const ERR_CODE = 500;
const EXPIRE_CODE = 1005; // 登录过期
const ERR_MSG = "暂无信息";
const SUCCESS_CODE = 200;
const SUCCESS_MSG = "请求成功";
/*
 * 网站配置
 */
if(!function_exists('website')){
    function website(): array {
        //标识
        $webiste = Config::get('app.web_unique').'website';
        //是否有缓存
        if(!Cache::has($webiste)){
            $system = System::getSystemInfo()->toArray();
            $system["webUnique"] = $webiste;
            Cache::set($webiste, $system);
        }
        $info = Cache::get($webiste);

        return $info;
    }
}
/*
 * 订阅过期回调方法
 */
if(!function_exists('keyCallback')) {
    function keyCallback($redis, $pattern, $chan, $msg): void {
        echo "Pattern: $pattern\n";
        echo "Channel: $chan\n";
        echo "Payload: $msg\n";
        //keyCallback为订阅事件后的回调函数，这里写业务处理逻辑，
        $order = explode('-', $msg);
        echo "订单号：" . $order[1] . "\n";
        echo "表名：" . $order[3] . "\n";
        echo "字段：" . $order[5] . "\n";
    }
}
/*
 * 唯一登录redis存放数组
 * @param array $info 登录管理员信息
 * @param string $key 标识名
 * @param string $idName id字段名
 */
if(!function_exists('setOnlyLogin')){
    function setOnlyLogin(array $info, string $key="sessionId", string $idName="ad_id"): array {
        //是否存在
        if(!Cache::has($key)){
            //创建一个数组，将id作为key把session_id作为值存到redis
            $sessionIds = [
                $info[$idName] => $info['sessionId']
            ];
        }else{
            //找到登录id 对应的session_id值并改变这个值
            $sessionIds = Cache::get($key);
            $sessionIds[$info[$idName]] = $info['sessionId'];
        }
        Cache::set($key, $sessionIds);

        return $sessionIds;
    }
}
/*
 * 唯一登录缓存存放数组检测
 * @param array $info 登录管理员信息
 * @param string $key 标识名
 * @param string $idName id字段名
 */
if(!function_exists('checkOnlyLogin')){
    function checkOnlyLogin(array $info, string $key="sessionId", string $idName="ad_id"): bool {
        //获取sessionId 数组
        $sessionIds = Cache::get($key);
        //如果redis数组消失，则重新创建
        if(!$sessionIds) $sessionIds = setOnlyLogin($info);
        //存入的session_id和登录的session_id相等则返回true
        if($sessionIds[$info[$idName]] == $info['sessionId']){
            return true;
        }else{
            return false;
        }
    }
}
/*
 * 20位唯一单号
 */
if(!function_exists('getOnlyNumber')){
    function getOnlyNumber(): string {
        $orderNo = date('YmdHis').substr(microtime(), 2, 1) . mt_rand(10000,99999);
        if(!empty($unique)) $orderNo = $orderNo.$unique;

        return $orderNo;
    }
}
/*
 * 生成用户编号
 */
if(!function_exists('getUserNumber')) {
    function getUserNumber(): string {
        $code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $rand = $code[rand(0, 25)]
            . strtoupper(dechex(date('m')))
            . date('d') . substr(time(), -5)
            . substr(microtime(), 2, 5)
            . sprintf('%02d', rand(0, 99));
        for (
            $a = md5($rand, true),
            $s = '0123456789ABCDEFGHIJKLMNOPQRSTUV',
            $d = '',
            $f = 0;
            $f < 8;
            $g = ord($a[$f]),
            $d .= $s[($g ^ ord($a[$f + 8])) - $g & 0x1F],
            $f++
        ) ;
        return $d;
    }
}
/**
 * 获取随机字符串
 */
if(!function_exists("getRandStr")) {
    function getRandStr(int $length, $specialChars = false): string {
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        if ($specialChars) $chars .= '!@#$%^&*()';
        $result = '';
        $max = strlen($chars) - 1;
        for ($i = 0; $i < $length; $i++) {
            $result .= $chars[rand(0, $max)];
        }
        return $result;
    }
}
/*
 * 检查字段是否为空
 * @param array $map 获取的数据
 * @param array $pass 允许为空的字段
 */
if(!function_exists('checkField')) {
    function checkField(array $map, array $pass=[]): void {
        foreach ($map as $key => $value) {
            if(!in_array($key, $pass)){
                if ($value == '' || $value == NULL) {
                    $data['info'] = $key.'请填写完整信息';
                    $data['status'] = 0;
                    exit(setJsonArray($data));
                }
            }
        }
    }
}
/*
 * 中断提示demo
 * @param string $alert 提示内容
 */
if(!function_exists('alertDemo')) {
    function alertDemo(string $alert): void {
        echo "<div style='text-align: center;font-size: 24px;color: #009688;margin-top: 15%;'>{$alert}</div>";
        exit();
    }
}
/*
 * 不中断提示demo
 * @param string $alert 提示内容
 */
if(!function_exists('alertDemoNotExit')) {
    function alertDemoNotExit(string $alert): void {
        echo "<div style='text-align: center;font-size: 24px;color: #009688;margin-top: 10%;'>{$alert}</div>";
    }
}
/*
 * 递归寻找下级，获得所在层级及排序后的数据
 * @param array $list 数据信息
 * @param string $pidFiled 父id字段名
 * @param int $idFiled 递归中传值的id字段名
 * @param int $pid 父id
 * @param int $level 所在层级
 * @param string $typeFiled 根据字段名返回的数据array=所有数据
 * @return array
 */
if(!function_exists('findChildLevel')){
    function findChildLevel(array $list, string $pidFiled, string $idFiled, int $pid=0, int $level=1 , string $typeFiled='array'): array {
        $array = [];
        foreach ($list as $key => $value) {
            if ($value[$pidFiled] == $pid) {
                //所在层级
                $value['level'] = $level;
                //赋值给创建数组
                if($typeFiled == 'array'){
                    $array[] = $value;
                }else{
                    $array[] = $value[$typeFiled];
                }
                $childArr = findChildLevel($list, $pidFiled, $idFiled, $value[$idFiled], $level+1, $typeFiled);
                if (is_array($childArr)) {
                    //合并数组
                    $array = array_merge($array, $childArr);
                }
            }
        }
        return $array;
    }
}
/*
 * 递归列表，重组数据，适用数据小量情况
 * @param array $list 数据
 * @param string $pidName 父id字段名
 * @param string $idName id字段名
 * @param string $labelName 名称的字段名
 * @param int $pid 父id
 * @return array
 */
if(!function_exists('getChildData')){
    function getChildData(array $list, string $pidName, string $idName, string $labelName, int $pid=0): array {
        $array = [];
        foreach ($list as $key => $value){
            if ($value[$pidName] == $pid){
                $data = [];
                $data['id'] = $value[$idName];
                $data['label'] = $value[$labelName];
                $data['children'] = getChildData($list, $pidName, $idName, $labelName, $value[$idName]);
                $array[] = $data;
            }
        }
        return $array;
    }
}
/*
 * PhpSpreadsheet导出数据
 * @param array $data A1标题
 * @param array $info 导出的数据
 * @param array $filed 导出的字段名字
 * @param int $output 输出类型
 */
if(!function_exists('exportData')) {
    function exportData(array $data, array $info, array $filed, int $output=0): array {
        /*
         *  示例
         *  $data = ['姓名','编号'];
         *  $filed = ['us_truename','us_number'];
         */
        set_time_limit(0);
        ini_set('memory_limit', '1024M');
        //导出数据
        $file_name = date('Y-m-d_His').'.xlsx';
        ob_clean();
        //引入Spreadsheet类
        //require_once __DIR__ . '/../vendor/autoload.php';
        $spreadsheet = new Spreadsheet();
        $objPHPExcel = $spreadsheet->getActiveSheet();
        header('Content-Type: application/vnd.ms-excel');
        header("Content-Disposition:attachment; filename=".$file_name);
        header('Cache-Control: max-age=0');
        //excel第一行
        $dataCount = count($data);

        for ($i = 'A', $k = 0; $i <= 'Z'; $i++, $k++) {
            if ($k == $dataCount) {
                break;
            }
            $objPHPExcel->SetCellValue($i . '1', $data[$k]);
        }
        //excel导出的数据填充
        $filedCount = count($filed);
        $n = 2;
        foreach ($info as $key => $value) {
            for ($i = 'A', $k = 0; $i <= 'Z'; $i++, $k++) {
                if ($k == $filedCount) {
                    break;
                }
                $objPHPExcel->SetCellValue($i.$n,' '.$value[$filed[$k]]);
            }
            $n++;
        }
        $objWriter = new Xlsx($spreadsheet);
        //文件保存路径
        $excel_path = Config::get('app.excel_url');
        $download_url = $excel_path.$file_name;
        //输出方式
        if($output == 0){
            //检查文件夹是否存在，不存在则创建
            if(!file_exists(Config::get('app.excel_url'))){
                mkdir($excel_path);
            }
            //输出指定目录
            $objWriter->save($download_url);
            //下载文件demo
            $result = downloadDemo($download_url, $file_name);
            //删除清空
            $spreadsheet->disconnectWorksheets();
            unset($spreadsheet);
            return $result;
        }else{
            $objWriter->save('php://output');//输出到浏览器
            exit();
        }
    }
}
/*
 * 导出excel layui下载demo
 * @param string $download_url 文件下载地址
 * @param string $file_name 文件名
 */
if(!function_exists('downloadDemo')) {
    function downloadDemo(string $download_url, string $file_name): array {
        //下载地址
        $url = Config::get('app.excel_down_url').$file_name;
        //下载html样式
        $data['info'] = '<div style="width:200px;margin:17% auto 0 auto;text-align:center;">
                            <a style="color:#5a98de;font-size:18px;" href="' . $url . '">点击下载</a>
                        </div>';
        $data['url'] = $download_url;
        $data['status'] = 1;
        return $data;
    }
}
/*
 * curl get方法
 * @param string $url 请求地址
 */
if(!function_exists('getCurl')) {
    function getCurl(string $url): array {
        $ch = curl_init();
        $timeout = 120;  //120秒未响应中断连接
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //屏蔽https检测
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//获取页面内容，不直接输出到页面 设置参数：1 或 true
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); //请求响应时间
        $json = curl_exec($ch);
        curl_close($ch);
		if(!$json) {
            $result = [];
        }else{
            //json解码
            $result = json_decode($json, true);
        }
        return $result;
    }
}
/*
 * 根据ip获取位置
 */
if(!function_exists('getPosition')) {
    function getPosition(): string {
        $ip = Request::ip();
        //高德IP地址API
        $gaoDeKey = "f7651b759716fc885d187e698c100513";
        $url = "https://restapi.amap.com/v3/ip?key=".$gaoDeKey."&ip=".$ip;
        //curl获取地址
        $result = getCurl($url);
        if (empty($result) || is_array($result['city'])) {
            $result['province'] = '未知';
            $result['city'] = '未知';
        }
        return $result['province'].$result['city'];
    }
}
/*
 * 单个文件上传
 * @param string $name 接收的name
 * @param string $path 文件保存路径
 * @param int $size 限制文件大小 默认10M
 * @param string $path 允许后缀
 */
if(!function_exists('uploadFile')){
    function uploadFile(string $name, string $path ,int $size=10 ,string $ext='jpg,png,gif,jpeg'): array {
        // M换算为byte
        $size = byteConversion($size, "M");
        // 获取表单上传文件 例如上传了001.jpg
        $file = request()->file($name);
        try {
            //验证规则
            validate(['file'=>['filesize'=>$size, 'fileExt'=>$ext]])->check(['file' => $file]);
            //移动文件保存
            $saveName = \think\facade\Filesystem::disk('upload')->putFile($path, $file, 'uniqid');
            // 成功上传后 获取上传信息
            $data['src'] = $saveName;
            $data['info'] = '上传成功';
            $data['status'] = 1;
        } catch (think\exception\ValidateException $e) {
            // 上传失败获取错误信息
            $data['info'] = $e->getMessage();
            $data['status'] = 0;
        }
        return $data;
    }
}
/*
 * 批量文件上传
 * @param string $name 接收的name
 * @param string $path 文件保存路径
 * @param int $size 限制文件大小 10M
 * @param string $ext 允许后缀
 */
if(!function_exists('uploadFileBatch')){
    function uploadFileBatch(string $name, string $path ,int $size=10 ,string $ext='jpg,png,gif,jpeg'): array {
        // M换算为byte
        $size = byteConversion($size, "M");
        //获取表单上传文件name
        $files = request()->file($name);
        try {
            //验证规则
            validate(['file'=>['filesize'=>$size, 'fileExt'=>$ext]])->check(['file' => $files]);
            //文件路径数组
            $saveName = [];
            foreach($files as $file){
                //移动文件保存
                $saveName[] = \think\facade\Filesystem::disk('upload')->putFile($path, $file, 'uniqid');
            }
            //成功上传后，获取上传信息
            $data['src'] = $saveName;
            $data['info'] = '上传成功';
            $data['status'] = 1;
        } catch (think\exception\ValidateException $e) {
            // 上传失败获取错误信息
            $data['info'] = $e->getMessage();
            $data['status'] = 0;
        }
        return $data;
    }
}
/*
 * 闭包回调函数 数组遍历转换
 */
if(!function_exists('arrayEach')){
    function arrayEach(array $array, callable $callable): array {
        foreach ($array as $key => $value){
            $array[$key] = $callable($value, $key); //回调赋值
        }
        return $array;
    }
}
/*
 * 获取富文本中第一张图片地址
 * @param string $content 文本内容
 */
if(!function_exists('getHtmlFirstImg')){
    function getHtmlFirstImg(string $content): string {
        $str = "";
        if(preg_match_all("/(src)=([\"|']?)([^ \"'>]+\.(gif|jpg|jpeg|bmp|png))\\2/i",$content,$matches)){
            $str = $matches[3][0];
            if (preg_match('/\/Uploads\/images/', $str)) {
                return $str = substr($str,7);
            }
            return $str;
        }
        return $str;
    }
}
/*
 * 将特定符合隔断的字符串转大驼峰写法
 * @param string $words 字符串
 * @param string $separator 特定符号
 */
if(!function_exists('camelize')) {
    function camelize(string $words, string $separator="_"){
        return str_replace(" ",false, ucwords(str_replace($separator," ", $words)));
    }
}
/*
 * 生成递增数字序列号
 * @param int $start 起始数
 * @param int $length 位数
 * @param string $prefix 前缀
 */
if(!function_exists("setSerialNumber")){
    function setSerialNumber(int $start=0, int $length=7, string $prefix=""){
        //我们通过str_pad()函数，把递增的$m组合成7位的字符串，长度不够则用0来凑齐
        return $prefix.str_pad($start, $length, '0', STR_PAD_LEFT);
    }
}
/*
 * 批量生成递增数字序列号
 * @param int $num 生成数量
 * @param int $start 起始数
 * @param int $length 位数
 * @param string $prefix 前缀
 */
if(!function_exists("setSerialNumberBatch")){
    function setSerialNumberBatch(int $num=100, int $start=0, int $length=7, string $prefix=""){
        //空数组
        $map = [];
        for($i = 0; $i<$num; $i++) {
            //每次循环，m都会递增
            $start = $start + 1;
            //我们通过str_pad()函数，把递增的$m组合成7位的字符串，长度不够则用0来凑齐
            $map[] = $prefix.str_pad($start, $length, '0', STR_PAD_LEFT);
        }
        return $map;
    }
}
/*
 * 其他单位转换字节
 * @param int $size 大小
 * @param string $unit 单位
 */
if(!function_exists("byteConversion")){
    function byteConversion(int $size, string $unit): int{
        //M => byte
        if($unit == "M"){
            $size = $size * 1024 * 1024;
        }
        return $size;
    }
}
/*
 * 格式化字节大小
 * @param  number $size      字节数
 * @param  string $delimiter 数字和单位分隔符
 * @return string            格式化后的带单位的大小
 */
if(!function_exists("formatBytes")) {
    function formatBytes($size, $delimiter = ''){
        $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
        for ($i = 0; $size >= 1024 && $i < 5; $i++) $size /= 1024;
        return round($size, 2) . $delimiter . $units[$i];
    }
}
/**
 * 设置状态返回数组
 * @param void $content 状态内容
 * @param int $status 状态值
 * @param array $other 其他数据值
 * @return array
 */
if(!function_exists("resInfo")) {
    function resInfo($content, int $status, array $other=[]): array {
        $info = ["info"=>$content, "status"=>$status];
        return empty($other) ? $info : array_merge($info, $other);
    }
}
/**
 * 统一格式返回
 */
if(!function_exists("resData")) {
    function resData($data, string $msg = SUCCESS_MSG, int $code = SUCCESS_CODE, array $other=[]): array {
        $info = ["msg" => $msg, "code" => $code, "data" => $data];
        return empty($other) ? $info : array_merge($info, $other);
    }
}
/**
 * 统一分页格式返回
 */
if(!function_exists("resPageData")) {
    function resPageData($data, string $msg = SUCCESS_MSG, int $code = SUCCESS_CODE): array {
        $page = [
            "current" => $data["current"] ?? 0,
            "pageSize" => $data["pageSize"] ?? 0,
            "total" => $data["total"] ?? 0,
        ];
        return resData($data["data"], $msg, $code, $page);
    }
}
/**
 * 分页数据转为分页格式返回
 */
if(!function_exists("covertPageData")) {
    function covertPageData($data, int $total, int $current = 1, int $pageSize = 10): array {
        return [
            "data" => $data,
            "current" => $current ?? 0,
            "pageSize" => $pageSize ?? 0,
            "total" => $total ?? 0,
        ];
    }
}
/**
 * 是否是手机
 */
if(!function_exists("isMobile")){
    function isMobile(): bool {
        return Request::isMobile();
    }
}
/*
 * 字符串转换为中文json
 * @param string $info 数据
 */
if(!function_exists('setJsonStr')){
    function setJsonStr(string $info): string{
        return json_encode($info, JSON_UNESCAPED_UNICODE);
    }
}
/*
 * 数组转换为中文json
 * @param array $info 数据
 */
if(!function_exists('setJsonArray')){
    function setJsonArray(array $info): string {
        return json_encode($info, JSON_UNESCAPED_UNICODE);
    }
}
